<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>学生成绩管理系统</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js"></script>

  <!-- Tailwind配置 -->
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#165DFF',
            secondary: '#36CFC9',
            accent: '#FF7D00',
            success: '#00B42A',
            warning: '#FF7D00',
            danger: '#F53F3F',
            info: '#86909C',
            light: '#F2F3F5',
            dark: '#1D2129',
          },
          fontFamily: {
            inter: ['Inter', 'system-ui', 'sans-serif'],
          },
        },
      }
    }
  </script>

  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .table-shadow {
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
      }
      .btn-hover {
        @apply transition-all duration-300;
      }
      .input-focus {
        @apply focus:ring-2 focus:ring-primary/30 focus:border-primary transition-all duration-200;
      }
      .card-hover {
        @apply hover:shadow-lg transition-all duration-300;
      }
    }
  </style>
</head>
<body class="bg-gray-50 font-inter min-h-screen">
  <div id="app" class="container mx-auto px-4 py-8 max-w-6xl">
    <!-- 顶部标题 -->
    <header class="mb-8">
      <h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-dark flex items-center">
        <i class="fa fa-graduation-cap text-primary mr-3"></i>
        学生成绩管理系统
      </h1>
      <p class="text-gray-500 mt-2">高效管理学生成绩，提升教学质量</p>
    </header>

    <!-- 操作区 -->
    <div class="bg-white rounded-xl p-6 mb-6 table-shadow">
      <div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4 mb-4">
        <div class="flex items-center gap-2">
          <button
            @click="sortBy('name')"
            class="btn-hover bg-primary/10 text-primary px-4 py-2 rounded-lg flex items-center"
          >
            <i class="fa fa-sort mr-2"></i>按姓名排序
          </button>
          <button
            @click="sortBy('math')"
            class="btn-hover bg-primary/10 text-primary px-4 py-2 rounded-lg flex items-center"
          >
            <i class="fa fa-sort-numeric-asc mr-2"></i>数学成绩
          </button>
          <button
            @click="sortBy('english')"
            class="btn-hover bg-primary/10 text-primary px-4 py-2 rounded-lg flex items-center"
          >
            <i class="fa fa-sort-alpha-asc mr-2"></i>英语成绩
          </button>
          <button
            @click="sortBy('average')"
            class="btn-hover bg-primary/10 text-primary px-4 py-2 rounded-lg flex items-center"
          >
            <i class="fa fa-sort-numeric-asc mr-2"></i>平均分
          </button>
        </div>

        <button
          @click="showAddModal = true"
          class="btn-hover bg-primary text-white px-6 py-2 rounded-lg flex items-center shadow-md hover:shadow-lg"
        >
          <i class="fa fa-plus mr-2"></i>添加学生
        </button>
      </div>

      <!-- 搜索框 -->
      <div class="relative max-w-md mx-auto">
        <input
          v-model="searchQuery"
          type="text"
          placeholder="搜索学生姓名..."
          class="w-full pl-10 pr-4 py-3 rounded-lg border border-gray-300 input-focus"
        >
        <i class="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
      </div>
    </div>

    <!-- 学生成绩表格 -->
    <div class="bg-white rounded-xl overflow-hidden table-shadow">
      <div class="overflow-x-auto">
        <table class="w-full">
          <thead>
            <tr class="bg-gray-50 text-left">
              <th class="px-6 py-4 font-semibold text-gray-600">#</th>
              <th class="px-6 py-4 font-semibold text-gray-600">姓名</th>
              <th class="px-6 py-4 font-semibold text-gray-600">数学</th>
              <th class="px-6 py-4 font-semibold text-gray-600">英语</th>
              <th class="px-6 py-4 font-semibold text-gray-600">平均分</th>
              <th class="px-6 py-4 font-semibold text-gray-600">操作</th>
            </tr>
          </thead>
          <tbody>
            <!-- 虚拟滚动实现 -->
            <template v-for="student in visibleStudents" :key="student.id">
              <tr class="border-b border-gray-100 hover:bg-gray-50 transition-colors duration-200">
                <td class="px-6 py-4 text-gray-600">{{ student.id }}</td>
                <td class="px-6 py-4">
                  <button
                    @click="showStudentDetails(student)"
                    class="text-primary hover:underline font-medium"
                  >
                    {{ student.name }}
                  </button>
                </td>
                <td class="px-6 py-4">
                  <span :class="getGradeClass(student.math)">{{ student.math }}</span>
                </td>
                <td class="px-6 py-4">
                  <span :class="getGradeClass(student.english)">{{ student.english }}</span>
                </td>
                <td class="px-6 py-4 font-medium">
                  <span :class="getGradeClass(student.average)">{{ student.average.toFixed(1) }}</span>
                </td>
                <td class="px-6 py-4">
                  <button
                    @click="deleteStudent(student.id)"
                    class="text-danger hover:text-danger/80 transition-colors"
                    title="删除学生"
                  >
                    <i class="fa fa-trash-o"></i>
                  </button>
                </td>
              </tr>
            </template>
          </tbody>
        </table>
      </div>

      <!-- 空状态 -->
      <div v-if="filteredStudents.length === 0" class="py-16 text-center">
        <div class="mx-auto w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mb-4">
          <i class="fa fa-search text-gray-400 text-3xl"></i>
        </div>
        <h3 class="text-xl font-medium text-gray-500">未找到学生</h3>
        <p class="text-gray-400 mt-2">尝试调整搜索条件或添加新学生</p>
      </div>

      <!-- 分页 -->
      <div v-if="filteredStudents.length > 0" class="px-6 py-4 flex justify-between items-center border-t border-gray-100">
        <div class="text-sm text-gray-500">
          显示 {{ visibleStudents.length }} 条，共 {{ filteredStudents.length }} 条
        </div>
        <div class="flex items-center gap-2">
          <button
            @click="currentPage = Math.max(1, currentPage - 1)"
            :disabled="currentPage === 1"
            class="btn-hover px-3 py-1 rounded border border-gray-300 text-gray-600 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="fa fa-chevron-left"></i>
          </button>

          <span class="px-3 py-1 rounded bg-primary text-white">
            {{ currentPage }}
          </span>

          <button
            @click="currentPage = Math.min(totalPages, currentPage + 1)"
            :disabled="currentPage === totalPages"
            class="btn-hover px-3 py-1 rounded border border-gray-300 text-gray-600 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="fa fa-chevron-right"></i>
          </button>
        </div>
      </div>
    </div>

    <!-- 添加学生模态框 -->
    <div v-if="showAddModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
      <div class="bg-white rounded-xl max-w-md w-full max-h-[90vh] overflow-y-auto animate-fade-in">
        <div class="p-6 border-b border-gray-100">
          <h3 class="text-xl font-bold text-dark">添加学生</h3>
        </div>

        <form @submit.prevent="addStudent">
          <div class="p-6 space-y-4">
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-1">姓名</label>
              <input
                v-model="newStudent.name"
                type="text"
                required
                class="w-full px-4 py-2 rounded-lg border border-gray-300 input-focus"
                placeholder="请输入学生姓名"
              >
            </div>

            <div>
              <label class="block text-sm font-medium text-gray-700 mb-1">数学成绩</label>
              <input
                v-model="newStudent.math"
                type="number"
                min="0"
                max="100"
                required
                class="w-full px-4 py-2 rounded-lg border border-gray-300 input-focus"
                placeholder="请输入数学成绩 (0-100)"
              >
              <p v-if="errors.math" class="text-danger text-xs mt-1">{{ errors.math }}</p>
            </div>

            <div>
              <label class="block text-sm font-medium text-gray-700 mb-1">英语成绩</label>
              <input
                v-model="newStudent.english"
                type="number"
                min="0"
                max="100"
                required
                class="w-full px-4 py-2 rounded-lg border border-gray-300 input-focus"
                placeholder="请输入英语成绩 (0-100)"
              >
              <p v-if="errors.english" class="text-danger text-xs mt-1">{{ errors.english }}</p>
            </div>
          </div>

          <div class="p-6 border-t border-gray-100 flex justify-end gap-3">
            <button
              @click="showAddModal = false"
              type="button"
              class="btn-hover px-5 py-2 rounded-lg border border-gray-300 text-gray-700 hover:bg-gray-50"
            >
              取消
            </button>
            <button
              type="submit"
              class="btn-hover px-5 py-2 rounded-lg bg-primary text-white hover:bg-primary/90 shadow-md hover:shadow-lg"
            >
              保存
            </button>
          </div>
        </form>
      </div>
    </div>

    <!-- 学生详情模态框 -->
    <div v-if="showDetailsModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
      <div class="bg-white rounded-xl max-w-md w-full max-h-[90vh] overflow-y-auto animate-fade-in">
        <div class="p-6 border-b border-gray-100">
          <h3 class="text-xl font-bold text-dark">学生详情</h3>
        </div>

        <div class="p-6 space-y-4">
          <div class="flex justify-between items-center py-2 border-b border-gray-100">
            <span class="text-gray-600">姓名</span>
            <span class="font-medium">{{ currentStudent.name }}</span>
          </div>

          <div class="flex justify-between items-center py-2 border-b border-gray-100">
            <span class="text-gray-600">数学成绩</span>
            <span class="font-medium">
              <span :class="getGradeClass(currentStudent.math)">{{ currentStudent.math }}</span>
            </span>
          </div>

          <div class="flex justify-between items-center py-2 border-b border-gray-100">
            <span class="text-gray-600">英语成绩</span>
            <span class="font-medium">
              <span :class="getGradeClass(currentStudent.english)">{{ currentStudent.english }}</span>
            </span>
          </div>

          <div class="flex justify-between items-center py-2 border-b border-gray-100">
            <span class="text-gray-600">平均分</span>
            <span class="font-medium">
              <span :class="getGradeClass(currentStudent.average)">{{ currentStudent.average.toFixed(1) }}</span>
            </span>
          </div>

          <!-- 成绩分布图表 -->
          <div class="pt-4">
            <h4 class="font-medium text-gray-700 mb-3">成绩分布</h4>
            <div class="space-y-2">
              <div>
                <div class="flex justify-between mb-1">
                  <span class="text-sm text-gray-600">数学</span>
                  <span class="text-sm font-medium">{{ currentStudent.math }}/100</span>
                </div>
                <div class="h-2 bg-gray-200 rounded-full overflow-hidden">
                  <div
                    class="h-full bg-primary rounded-full"
                    :style="{ width: `${currentStudent.math}%` }"
                  ></div>
                </div>
              </div>

              <div>
                <div class="flex justify-between mb-1">
                  <span class="text-sm text-gray-600">英语</span>
                  <span class="text-sm font-medium">{{ currentStudent.english }}/100</span>
                </div>
                <div class="h-2 bg-gray-200 rounded-full overflow-hidden">
                  <div
                    class="h-full bg-secondary rounded-full"
                    :style="{ width: `${currentStudent.english}%` }"
                  ></div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <div class="p-6 border-t border-gray-100 flex justify-end">
          <button
            @click="showDetailsModal = false"
            class="btn-hover px-5 py-2 rounded-lg border border-gray-300 text-gray-700 hover:bg-gray-50"
          >
            关闭
          </button>
        </div>
      </div>
    </div>

    <!-- 提示信息 -->
    <div
      v-if="showToast"
      class="fixed bottom-4 right-4 bg-dark text-white px-6 py-3 rounded-lg shadow-lg flex items-center z-50 animate-fade-in"
    >
      <i class="fa fa-check-circle mr-2"></i>
      {{ toastMessage }}
    </div>
  </div>

  <script>
    const { createApp, ref, computed, watch } = Vue;

    createApp({
      setup() {
        // 学生数据
        const students = ref([
          { id: 1, name: "张三", math: 90, english: 85 },
          { id: 2, name: "李四", math: 78, english: 92 },
          { id: 3, name: "王五", math: 85, english: 76 },
          { id: 4, name: "赵六", math: 92, english: 88 },
          { id: 5, name: "钱七", math: 65, english: 70 },
          { id: 6, name: "孙八", math: 88, english: 95 },
          { id: 7, name: "周九", math: 72, english: 68 },
          { id: 8, name: "吴十", math: 95, english: 89 },
          { id: 9, name: "郑十一", math: 68, english: 75 },
          { id: 10, name: "王十二", math: 83, english: 81 },
          { id: 11, name: "陈十三", math: 79, english: 83 },
          { id: 12, name: "杨十四", math: 87, english: 79 },
          { id: 13, name: "黄十五", math: 91, english: 86 },
          { id: 14, name: "周十六", math: 74, english: 77 },
          { id: 15, name: "吴十七", math: 89, english: 90 },
          { id: 16, name: "郑十八", math: 76, english: 82 },
          { id: 17, name: "王十九", math: 84, english: 73 },
          { id: 18, name: "陈二十", math: 93, english: 87 },
          { id: 19, name: "杨二十一", math: 71, english: 69 },
          { id: 20, name: "黄二十二", math: 86, english: 91 },
        ]);

        // 计算每个学生的平均分
        watch(students, () => {
          students.value.forEach(student => {
            student.average = (student.math + student.english) / 2;
          });
        }, { immediate: true });

        // 排序相关
        const sortField = ref('id');
        const sortDirection = ref('asc');

        // 搜索相关
        const searchQuery = ref('');

        // 过滤后的学生列表
        const filteredStudents = computed(() => {
          if (!searchQuery.value) {
            return [...students.value];
          }

          const query = searchQuery.value.toLowerCase();
          return students.value.filter(student =>
            student.name.toLowerCase().includes(query)
          );
        });

        // 分页相关
        const itemsPerPage = ref(10);
        const currentPage = ref(1);

        const totalPages = computed(() => {
          return Math.ceil(filteredStudents.value.length / itemsPerPage.value);
        });

        // 虚拟滚动 - 只渲染可见区域的学生
        const visibleStudents = computed(() => {
          const startIndex = (currentPage.value - 1) * itemsPerPage.value;
          const endIndex = startIndex + itemsPerPage.value;
          return filteredStudents.value.slice(startIndex, endIndex);
        });

        // 添加学生模态框
        const showAddModal = ref(false);
        const newStudent = ref({ name: '', math: '', english: '' });
        const errors = ref({ math: '', english: '' });

        // 学生详情模态框
        const showDetailsModal = ref(false);
        const currentStudent = ref({});

        // 提示信息
        const showToast = ref(false);
        const toastMessage = ref('');

        // 排序函数
        const sortBy = (field) => {
          if (sortField.value === field) {
            sortDirection.value = sortDirection.value === 'asc' ? 'desc' : 'asc';
          } else {
            sortField.value = field;
            sortDirection.value = 'asc';
          }

          students.value.sort((a, b) => {
            if (a[field] < b[field]) {
              return sortDirection.value === 'asc' ? -1 : 1;
            }
            if (a[field] > b[field]) {
              return sortDirection.value === 'asc' ? 1 : -1;
            }
            return 0;
          });
        };

        // 添加学生
        const addStudent = () => {
          // 验证成绩
          let isValid = true;
          errors.value = { math: '', english: '' };

          if (newStudent.value.math < 0 || newStudent.value.math > 100 || isNaN(newStudent.value.math)) {
            errors.value.math = '请输入0-100之间的有效成绩';
            isValid = false;
          }

          if (newStudent.value.english < 0 || newStudent.value.english > 100 || isNaN(newStudent.value.english)) {
            errors.value.english = '请输入0-100之间的有效成绩';
            isValid = false;
          }

          if (!isValid) return;

          // 添加新学生
          const newId = Math.max(...students.value.map(s => s.id), 0) + 1;
          students.value.push({
            id: newId,
            name: newStudent.value.name,
            math: parseFloat(newStudent.value.math),
            english: parseFloat(newStudent.value.english),
            average: (parseFloat(newStudent.value.math) + parseFloat(newStudent.value.english)) / 2
          });

          // 重置表单并关闭模态框
          newStudent.value = { name: '', math: '', english: '' };
          showAddModal.value = false;

          // 显示成功提示
          showToastMessage('学生添加成功');
        };

        // 删除学生
        const deleteStudent = (id) => {
          if (confirm('确定要删除该学生吗？')) {
            students.value = students.value.filter(student => student.id !== id);
            showToastMessage('学生删除成功');
          }
        };

        // 显示学生详情
        const showStudentDetails = (student) => {
          currentStudent.value = { ...student };
          showDetailsModal.value = true;
        };

        // 显示提示信息
        const showToastMessage = (message) => {
          toastMessage.value = message;
          showToast.value = true;

          setTimeout(() => {
            showToast.value = false;
          }, 3000);
        };

        // 根据成绩获取对应的CSS类
        const getGradeClass = (grade) => {
          if (grade >= 90) return 'text-success font-medium';
          if (grade >= 80) return 'text-primary font-medium';
          if (grade >= 70) return 'text-info font-medium';
          if (grade >= 60) return 'text-warning font-medium';
          return 'text-danger font-medium';
        };

        return {
          students,
          searchQuery,
          filteredStudents,
          visibleStudents,
          sortBy,
          addStudent,
          deleteStudent,
          showStudentDetails,
          getGradeClass,
          showAddModal,
          newStudent,
          errors,
          showDetailsModal,
          currentStudent,
          showToast,
          toastMessage,
          currentPage,
          totalPages
        };
      }
    }).mount('#app');
  </script>
</body>
</html>